﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using super_scrable.Models;
using super_scrable.Views.Widgets;
using super_scrable.Models.Exceptions;

namespace super_scrable.Views
{
    public partial class Gameboard : Form
    {
        private Matrix matrix;
        private GameInfo info;

        private WordConstructor wordInConstruction;

        private Player currentPlayer;

        public Gameboard(GameInfo info)
        {
            Thread t = new Thread(new ThreadStart(this.showLoader));
            t.Start();//lancement loading screen

            InitializeComponent();
            this.info = info;
            this.currentPlayer = info.getPlayer(0);

            this.wordInConstruction = new WordConstructor();

            loadDataAndGrid();
            initLettersForPlayer(info);
            Word.InitializeStatic();

            t.Abort();//fermeture du loading screen
        }

        /*
         * Main => Case
         * 
         */
        private void onCaseDragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(LetterZone)))//drop LetterZone
            {
                LetterZone l = (LetterZone)e.Data.GetData(typeof(LetterZone));
                char letter = l.Letter;
                int value = l.Value;

                try
                {
                    //(sender as Case).setLetter(letter, value);
                    (sender as Case).showPiece();
                    FillCase(l, (sender as Case));
                    updateWordInConstruction((sender as Case));
                    l.hidePiece();
                }
                catch (AlreadyFillException)
                {
                    MessageBox.Show("Case déjà occupée.");
                }
            }
            else if (e.Data.GetDataPresent(typeof(Case)))
            {//drop case (case du jeu) : switch piece dans tableau de jeu
                if (sender is Case)//si changement de piece dans le gameboard
                {
                    try
                    {
                        SwitchLetter((Case)e.Data.GetData(typeof(Case)), (sender as Case));
                    }
                    catch (NullReferenceException)
                    {
                        MessageBox.Show("Déplacement non autorisé.");
                    }
                }
            }
        }

        private void updateWordInConstruction(Case selectedCase)
        {
            wordInConstruction.AddCase(selectedCase);
            updateWordInConstructionDisplay();
        }

        private void updateWordInConstructionDisplay()
        {
            //wordInConstruction.Value = wordInConstruction.GetWordMultiplicator();

            /*lblWord.Text = wordInConstruction.GetWord().ToString();
            lblWordMultiplicator.Text = wordInConstruction.GetWordMultiplicator().ToString();
            lblScore.Text = wordInConstruction.GetWordValue().ToString();*/
        }

        /**
         * Event DragEnter 
         */
        private void initDragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }

        /**
         * Init Drag de piece 
         * 
         */
        private void onDragLetter(object sender, MouseEventArgs e)
        {
            this.console_label.Text = "Glissement de la lettre '' en cours";
            if (sender is LetterZone && (sender as LetterZone).VisibleLetter)
                DoDragDrop((sender as LetterZone), DragDropEffects.Copy);
            else if (sender is Case && (sender as Case).VisibleLetter)
                DoDragDrop((sender as Case), DragDropEffects.Copy);

        }

        private void initLettersForPlayer(GameInfo info)
        {

            Random r = new Random();
            for (int i = 0; i < info.getPlayerNumber(); i++)
            {
                Player player = info.getPlayer(i);

                for (int j = 0; j < 7; j++)
                {
                    player.addLetter(new Letter((char)((r.Next(26) + 65))));
                }
            }

            this.piece1.Letter = info.getPlayer(0).getLetter(0).Character;
            this.piece1.Value = info.getPlayer(0).getLetter(0).Point;

            this.piece2.Letter = info.getPlayer(0).getLetter(1).Character;
            this.piece2.Value = info.getPlayer(0).getLetter(1).Point;

            this.piece3.Letter = info.getPlayer(0).getLetter(2).Character;
            this.piece3.Value = info.getPlayer(0).getLetter(2).Point;

            this.piece4.Letter = info.getPlayer(0).getLetter(3).Character;
            this.piece4.Value = info.getPlayer(0).getLetter(3).Point;

            this.piece5.Letter = info.getPlayer(0).getLetter(4).Character;
            this.piece5.Value = info.getPlayer(0).getLetter(4).Point;

            this.piece6.Letter = info.getPlayer(0).getLetter(5).Character;
            this.piece6.Value = info.getPlayer(0).getLetter(5).Point;

            this.piece7.Letter = info.getPlayer(0).getLetter(6).Character;
            this.piece7.Value = info.getPlayer(0).getLetter(6).Point;

            this.console_label.Text = info.getPlayer(0).getLetter(6).Point.ToString();
            this.label_current_player.Text = info.getPlayer(0).Pseudo;
            this.label_current_score.Text = info.getPlayer(0).Points.ToString();
        }

        private void loadLettersForPlayer(Player player)
        {
            showAllHandPiece();
            //check if 7 piece
            //si not generate new piece
            this.piece1.Letter = player.getLetter(0).Character;
            this.piece1.Value = player.getLetter(0).Point;

            this.piece2.Letter = player.getLetter(1).Character;
            this.piece2.Value = player.getLetter(1).Point;

            this.piece3.Letter = player.getLetter(2).Character;
            this.piece3.Value = player.getLetter(2).Point;

            this.piece4.Letter = player.getLetter(3).Character;
            this.piece4.Value = player.getLetter(3).Point;

            this.piece5.Letter = player.getLetter(4).Character;
            this.piece5.Value = player.getLetter(4).Point;

            this.piece6.Letter = player.getLetter(5).Character;
            this.piece6.Value = player.getLetter(5).Point;

            this.piece7.Letter = player.getLetter(6).Character;
            this.piece7.Value = player.getLetter(6).Point;

        }

        private void button_passe_tour_Click(object sender, EventArgs e)
        {
            currentPlayer.setLetters(getLetterInHand());
            info.Round += 1;
            this.currentPlayer = info.getPlayer(info.Round % info.getPlayerNumber());
            if (this.currentPlayer.getNumberPiecesInHand() < 7)
                this.currentPlayer.generateMissingPiece();

            loadLettersForPlayer(this.currentPlayer);
            //debug test init
            this.label_current_player.Text = currentPlayer.Pseudo;
            this.label_current_score.Text = currentPlayer.Points.ToString();

        }

        /**
         * Depot de piece dans la zone d'échange
         * 
         */
        private void exchangePlaceDragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(LetterZone)))//drop LetterZone
            {
                LetterZone l = (LetterZone)e.Data.GetData(typeof(LetterZone));
                l.Letter = ' ';
                l.Value = 0;
                this.console_label.Text = "letter " + l.Letter + " change";
                l.hidePiece();
            }
        }

        /**
         * Inverse 2 lettres dans la main + zone jeux => main
         *          
        */
        private void exchangePiecePlace(object sender, DragEventArgs e)
        {
            LetterZone letter_source = null;
            if (e.Data.GetDataPresent(typeof(LetterZone)))//drop LetterZone
                letter_source = (LetterZone)e.Data.GetData(typeof(LetterZone));
            else if (e.Data.GetDataPresent(typeof(Case)))
                letter_source = (LetterZone)e.Data.GetData(typeof(Case));
            else
                return;

            LetterZone letter_dest = (sender as LetterZone);
            char tmp_letter = letter_source.Letter;
            int tmp_value = letter_source.Value;
            Boolean tmp_enable = letter_source.VisibleLetter;

            //switch dest => src
            if (letter_dest.VisibleLetter)
                letter_source.showPiece();
            else
            {
                if (letter_source is Case)
                {//cas où case => main & vers place vide dans main
                    (letter_source as Case).DeleteLetter();
                }

                letter_source.hidePiece();
            }
            letter_source.Letter = letter_dest.Letter;
            letter_source.Value = letter_dest.Value;

            //switch src => dest
            if (tmp_enable)
                letter_dest.showPiece();
            else
                letter_dest.hidePiece();
            letter_dest.Letter = tmp_letter;
            letter_dest.Value = tmp_value;



            //this.console_label.Text = "switch letter";
        }

        private void FillCase(LetterZone letterZone, Case targetedCase)
        {

            if (wordInConstruction.CanBePlaced(targetedCase))
                targetedCase.setLetter(new Letter(letterZone.Letter));
        }

        private void SwitchLetter(Case letterSource, Case letterDest)
        {
            if (wordInConstruction.IsFilled(letterSource))
                throw new UnownedLetter();

            if (wordInConstruction.CanBePlaced(letterDest))
                throw new InvalidDirectionException();

            /*Case tmpCase = letterDest;

            MouveLetter(letterSource,letterDest);
            MouveLetter(tmpCase, letterSource);*/


            Letter tmpLetter = letterSource.getLetter();
            Boolean tmp_enable = letterSource.VisibleLetter;

            //switch dest => src
            letterSource.DeleteLetter();
            letterSource.setLetter(letterDest.getLetter());

            //switch src => dest
            letterDest.DeleteLetter();
            letterDest.setLetter(tmpLetter);
        }

        private void showAllHandPiece()
        {
            this.piece1.showPiece();
            this.piece2.showPiece();
            this.piece3.showPiece();
            this.piece4.showPiece();
            this.piece5.showPiece();
            this.piece6.showPiece();
            this.piece7.showPiece();
        }

        public List<Letter> getLetterInHand()
        {
            List<Letter> main = new List<Letter>();

            if (this.piece1.VisibleLetter)
                main.Add(new Letter(this.piece1.Letter));

            if (this.piece2.VisibleLetter)
                main.Add(new Letter(this.piece2.Letter));

            if (this.piece3.VisibleLetter)
                main.Add(new Letter(this.piece3.Letter));

            if (this.piece4.VisibleLetter)
                main.Add(new Letter(this.piece4.Letter));

            if (this.piece5.VisibleLetter)
                main.Add(new Letter(this.piece5.Letter));

            if (this.piece6.VisibleLetter)
                main.Add(new Letter(this.piece6.Letter));

            if (this.piece7.VisibleLetter)
                main.Add(new Letter(this.piece7.Letter));

            return main;
        }
    }
}
